<?php

use app\adaptor\Adaptee;
use app\adaptor\ClassAdaptor;
use app\adaptor\ObjectAdaptor;

require "../vendor/autoload.php";
ini_set('display_errors', 1);    //展示错误信息
error_reporting(E_ALL);    //展示所有错误信息

//建造者模式
/**
 * 建造者模式主要解决类的构造方法传入很多参数
 * 并且参数可能需要判断的造成的问题代码不易读，不易扩展的问题
 */
//$birdBuilder = new \app\builder\BirdBuilder();
//$blueBird = $birdBuilder->setHead('蓝色')->setWing('蓝色')->setFoot('黑色')->getBird();
//$blueBird->show();

//代理模式
/**
 * 代理模式主要是在不修改原本类的情况下，为类增加附加功能
 */
//$test = new \app\proxy\Test();
//$testProxy = new \app\proxy\RuntimeProxy($test);
//echo $testProxy->index(100000000);

//桥接模式
/**
 * 桥接模式主要通过组合解决不同的对象和不同的行为之间耦合问题
 * 比如，发送信息有2种方式：手机和邮件，警告类型有3种：通知，警告，错误
 * 如果每种情况单独写一个类需要写6个类，即：通知-手机，通知-邮件，警告-手机，警告-邮件，错误-手机，错误-邮件
 * 如果增加一种信息发送方式（微信），就需要再写3个类：通知-微信，警告-微信，错误-微信
 * 使用桥接模式，可以减少类的数量，易扩展
 * 如果再增加一种发送信息的方式(微信)，只需要再增加一个WechatMsgSender
 */
// $telephoneMsgSender = new \app\bridge\TelephoneMsgSender(['13112345678','17112345678']);
// $normalNotification = new \app\bridge\NoticeNotification($telephoneMsgSender);
// $normalNotification->notify('ssss');

//装饰器模式
//$data = [
//    'name' => 'xiaoming',
//    'gender' => 'male',
//    'age' => 30,
//];
//
//$webService = new \app\decorator\WebService($data);
//$xml = (new \app\decorator\RenderToXml($webService))->renderData();
//$json = (new \app\decorator\RenderToJson($webService))->renderData();
//echo $xml . PHP_EOL;
//echo $json . PHP_EOL;

//适配器模式
/**
 * 适配器模式的应用场景
 * 1：封装有缺陷的接口设计；
 * 2：统一多个类的接口设计；
 * 3：替换依赖的外部系统；
 * 4：兼容老版本接口；
 * 5：适配不同格式的数据
 * 适配器模式的实现方式
 * 1：类适配器-继承   Adaptee 接口很多，而且 Adaptee 和 ITarget 接口定义大部分都相同
 * 2：对象适配器-组合  Adaptee 接口很多，而且 Adaptee 和 ITarget 接口定义大部分都不相同
 */

//类适配器
//$classAdaptor = new ClassAdaptor();
//$classAdaptor->f1();
//$classAdaptor->f2();
//$classAdaptor->fc();

//对象适配器
//$adaptee = new Adaptee;
//$objAdaptor = new ObjectAdaptor($adaptee);
//$objAdaptor->f1();
//$objAdaptor->f2();
//$objAdaptor->fc();

//门面模式
/**
 * 门面模式又称外观模式，用来隐藏系统的复杂性，并向客户端提供一个统一的接口去访问多个子系统的多个不同接口，使子系统更加容易使用
 * 比如购买商品涉及购物车添加商品，订单的创建，支付，如果客户端分别去调用三个系统的三个接口就比较繁琐，并且因为增加网络IO
 * 可以为客户端提供一个高层的接口，一次实现购物车添加商品，创建订单和支付的操作
 */
//$facade = new \app\facade\Facade();
//$facade->buy();
//$facade->cancel();

//匿名函数类
/**
 * 匿名函数类可以通过bindTo方法获取/修改传入对象的属性，或者调用传入对象的方法
 * 是否有权限修改protected/private属性根据bindTo方法的第二个参数确定
 */
/*$test = new \app\closure\Test();
$test->addRoute('/user/test', function () {
    $this->bb = '1234';
});

$test->dispatch('/user/test');*/

/**
 * IOC容器通过bind和make方法绑定和解析对象
 * bind方法的第二个参数如果是闭包，则绑定的值为Closure类，属性parameter的键为闭包的参数
 * call_user_func_array(callback $callback,array $param_arr)
 * call_user_func_array调用第一个参数的回调函数，并将第二个参数传递给回调函数
 */
//$container = new \app\container\Container();
//
//$container->bind('superman', function($container, $moduleName) {
//    return new \app\container\SuperMan($container->make($moduleName));
//});
//
//$container->bind('xpower', function($container) {
//    return new \app\container\XPower();
//});
//
//$container->bind('flight', function($container) {
//    return new \app\container\Flight();
//});

/**
 * 1.make方法中的call_user_func_array先调用superman绑定的回调函数
 * 2.make方法中的call_user_func_array再调用xpower中绑定的回调函数，返回XPower类的实例对象
 * 3.返回的XPower的实例对象传递给SuperMan的构造函数
 * 4.返回SuperMan的实例对象
 */
//$superman_1 = $container->make('superman', ['xpower']);
//$superman_2 = $container->make('superman', ['flight']);
//
//var_dump($superman_1,$superman_2);

/**
 * 组合模式
 */
$c1 = new \app\composite\Company('阿里巴巴杭州总公司');
$hr = new \app\composite\HumanResource('人力资源部门');
$commerce = new \app\composite\Commerce('商务部门');

$c1->add($hr);
$c1->add($commerce);

$c2 = new \app\composite\Company('阿里巴巴四川分公司');
$c2->add($hr);
$c2->add($commerce);
$c1->add($c2);

$c3 = new \app\composite\Company('阿里巴巴湖北分公司');
$c3->add($hr);
$c3->add($commerce);
$c1->add($c3);

$c4 = new \app\composite\Company('阿里巴巴成都分公司');
$c4->add($hr);
$c4->add($commerce);
$c2->add($c4);

$c5 = new \app\composite\Company('阿里巴巴武汉分公司');
$c5->add($hr);
$c5->add($commerce);
$c3->add($c5);

$c1->show();

$c1->work();
